package script

import (
	"sync"

	"go.uber.org/zap"

	"github.com/yuin/gluamapper"
	lua "github.com/yuin/gopher-lua"
)

type crc struct {
	once  sync.Once
	table []uint16
}

var crcTb crc

// ByteArrayTemplate 统一的字节数组模板
type ByteArrayTemplate struct {
	Variable []*byte `json:"Variable"`
}

// initTable 初始化CRC表
func (c *crc) initTable() {
	crcPoly16 := uint16(0xa001)
	c.table = make([]uint16, 256)

	for i := uint16(0); i < 256; i++ {
		crc := uint16(0)
		b := i

		for j := uint16(0); j < 8; j++ {
			if ((crc ^ b) & 0x0001) > 0 {
				crc = (crc >> 1) ^ crcPoly16
			} else {
				crc = crc >> 1
			}
			b = b >> 1
		}
		c.table[i] = crc
	}
}

// crc16 计算CRC16校验值
func crc16(bs []byte) uint16 {
	crcTb.once.Do(crcTb.initTable)

	val := uint16(0xFFFF)
	for _, v := range bs {
		val = (val >> 8) ^ crcTb.table[(val^uint16(v))&0x00FF]
	}
	return val
}

// extractBytesFromLuaTable 从Lua表中提取字节数组
func extractBytesFromLuaTable(lv *lua.LTable) ([]byte, error) {
	template := ByteArrayTemplate{}
	if err := gluamapper.Map(lv, &template); err != nil {
		return nil, err
	}

	// 预分配字节切片
	result := make([]byte, 0, len(template.Variable))
	for _, v := range template.Variable {
		if v != nil {
			result = append(result, *v)
		}
	}

	return result, nil
}

// crcLuaFunction 统一的CRC计算Lua函数
func crcLuaFunction(L *lua.LState, littleEndian bool) int {
	lv := L.ToTable(1)
	if lv == nil {
		zap.S().Warn("Invalid Lua table parameter")
		L.Push(lua.LNumber(0))
		return 1
	}

	bytes, err := extractBytesFromLuaTable(lv)
	if err != nil {
		zap.S().Warnf("Failed to extract bytes from Lua table: %v", err)
		L.Push(lua.LNumber(0))
		return 1
	}

	crc := crc16(bytes)

	// 如果需要小端序，转换字节序
	if littleEndian {
		crc = (crc&0x00FF)*256 + (crc / 256)
	}

	L.Push(lua.LNumber(crc))
	return 1
}

// GetCRCModbus 获取Modbus CRC校验值
func GetCRCModbus(L *lua.LState) int {
	return crcLuaFunction(L, false)
}

// CheckCRCModbus 检查Modbus CRC校验值（功能与GetCRCModbus相同）
func CheckCRCModbus(L *lua.LState) int {
	return crcLuaFunction(L, false)
}

// GetCRCModbusLittleEndian 获取小端序Modbus CRC校验值
func GetCRCModbusLittleEndian(L *lua.LState) int {
	return crcLuaFunction(L, true)
}

// LuaCallNewVariables 调用Lua的NewVariables函数（保留原有功能）
func LuaCallNewVariables(L *lua.LState) {
	// 调用NewVariables
	err := L.CallByParam(lua.P{
		Fn:      L.GetGlobal("NewVariables"),
		NRet:    1,
		Protect: true,
	})
	if err != nil {
		zap.S().Errorf("Failed to call NewVariables: %v", err)
		return
	}

	// 获取返回结果
	ret := L.Get(-1)
	L.Pop(1)

	switch ret.(type) {
	case lua.LString:
		zap.S().Info("NewVariables returned string")
	case *lua.LTable:
		zap.S().Info("NewVariables returned table")

		// 解析变量结构
		type VariableTemplate struct {
			Index int    `json:"Index"`
			Name  string `json:"Name"`
			Label string `json:"Label"`
			Type  string `json:"Type"`
		}

		type VariableMapTemplate struct {
			Variable []*VariableTemplate `json:"Variable"`
		}

		variableMap := VariableMapTemplate{}
		if err := gluamapper.Map(ret.(*lua.LTable), &variableMap); err != nil {
			zap.S().Errorf("Failed to map variables: %v", err)
			return
		}

		// 输出变量信息
		for _, v := range variableMap.Variable {
			if v != nil {
				zap.S().Infof("Variable Label: %s", v.Label)
			}
		}
	default:
		zap.S().Warn("NewVariables returned unexpected type")
	}
}
